#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int n, m;
#define int long long

// 计算达到目标维生素值x所需的最小花费
// item: 包含维生素值和价格的物品列表
int cal(int x, vector<array<int, 2>> item) {
  // 使用一维dp数组进行空间优化，dp[j]表示花费为j时能获得的最大维生素值
  vector<int> dp(m + 5);

  // 01背包问题：遍历每个物品
  for (auto [a, c] : item) {
    // 从大到小遍历价格，避免重复选择同一物品
    for (int i = m; i >= c; i--)
      dp[i] = max(dp[i], dp[i - c] + a);
  }

  // 找到第一个满足维生素值>=x的最小花费
  for (int i = 0; i <= m; i++) {
    if (dp[i] >= x)
      return i;
  }
  return -1; // -1表示无法达到目标值x
}

// 三种维生素的物品列表
vector<array<int, 2>> vec[4];

// 检查是否能在预算m内达到维生素值x
int check(int x) {
  int ans = 0;
  // 分别计算三种维生素达到x所需的最小花费
  for (int i = 1; i <= 3; i++) {
    int val = cal(x, vec[i]);
    if (val == -1)
      return 0; // 如果某种维生素无法达到x，返回false
    ans += val;
    // cout << i << ' ' << val << endl; // 调试用，显示每种维生素的花费
  }
  // 检查总花费是否在预算范围内
  return ans <= m;
}

signed main() {
  cin >> n >> m;

  // 读取输入数据，按维生素类型分类存储
  for (int i = 1; i <= n; i++) {
    int v, a, c;
    cin >> v >> a >> c;
    vec[v].push_back({a, c}); // v: 维生素类型, a: 维生素值, c: 价格
  }

  // 二分查找最大可达到的维生素值
  int l = 0, r = 1e9, ans = 0;
  while (l <= r) {
    int mid = l + r >> 1; // 等价于 (l + r) / 2
    if (check(mid)) {
      ans = mid; // 当前mid可行，尝试更大的值
      l = mid + 1;
    } else {
      r = mid - 1; // 当前mid不可行，尝试更小的值
    }
  }
  cout << ans << endl;
}